#include <linux/module.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/gpio.h>
#include <linux/uaccess.h>
#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/wait.h>
#include <linux/sched.h>

static int major;
static struct class *hc_beep_class;
struct gpio_desc *beep_desc;

static ssize_t beep_write (struct file *filp, const char __user *buf, size_t size, loff_t *offset)
{
	int  err;
	char val;
	err = copy_from_user(&val, buf, 1);
	gpiod_set_value(beep_desc, val);  // val 只要非零就为有效状态
	return 0;
}

static int beep_open (struct inode *node, struct file *filp)
{
	gpiod_set_value(beep_desc, 0);
	return 0;
}

static struct file_operations beep_ops = {
	.owner 		=	THIS_MODULE,
	.open 		=   beep_open,
	.write 		=   beep_write,
};

/*=============================platform_driver==============================*/
/* 匹配内核根据设备树生成的platform_device */
static int my_probe(struct platform_device *pdev)
{
	struct device dev = pdev->dev;

	/* 从设备树中获取gpio */
 	beep_desc = gpiod_get(&dev, "beep");

	/* 设置GPIO方向 */
	gpiod_direction_output(beep_desc, 1);

	printk("my_probe run\n");
	
	return 0;
}

static int my_remove(struct platform_device *pdev)
{
	gpiod_set_value(beep_desc, 0);
	/* 释放GPIO */
	gpiod_put(beep_desc);
	printk("my_remove run\n");

	return 0;
}

static struct of_device_id hc_beep_match[] = {
	{.compatible = "hc-beep"}, 
	{},
};

static struct platform_driver beep_driver = {
	.probe		=	my_probe,	
	.remove		= 	my_remove,
	.driver		= {
		.name	= "beep_platform_driver",
		.of_match_table = hc_beep_match,
	},
};

/*=============================驱动出入口函数==============================*/
/* 驱动入口函数：insmod xx.ko 时会被调用 */
static int beep_init(void)
{	
	major = register_chrdev(0, "beep_driver", &beep_ops);
	
	hc_beep_class = class_create(THIS_MODULE, "beep_class");
	if(IS_ERR(hc_beep_class)){
		printk("hc_beep_class create faibeep\n");
		return 1;
	}

	device_create(hc_beep_class, NULL, MKDEV(major, 0), NULL, "beep");

	platform_driver_register(&beep_driver);

	return 0;
}

/* 驱动出口函数： rmmod xx.ko 时会被调用 */
static void beep_exit(void)
{
	platform_driver_unregister(&beep_driver);
	
	device_destroy(hc_beep_class, MKDEV(major, 0));
	
	class_destroy(hc_beep_class);
	
	unregister_chrdev(major, "beep_driver");
	
	printk("hc_beep driver exit\n");
}

module_init(beep_init);
module_exit(beep_exit);
MODULE_LICENSE("GPL");


